home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / dviware / dvi2tty / dvistuff.c < prev    next >
C/C++ Source or Header  |  1995-01-12  |  38KB  |  1,144 lines

  1.  
  2. #include "dvi2tty.h"
  3. #include <sys/types.h>
  4. #include <sys/stat.h>
  5. #if defined(VMS) 
  6. #include types.h
  7. #include stat
  8. #endif
  9. #if defined(MSDOS)
  10. #include <math.h>
  11. #endif
  12. #include "commands.h"
  13.  
  14. #if defined(VMS) 
  15. #define mseek vmsseek
  16. #define ROUND(a)        (a>=0.0 ?  (int) (a + 0.5) : (int) (a - 0.5) )
  17. #else
  18. #define mseek fseek
  19. #endif
  20.  
  21. #define VERSIONID            2 /* dvi version number that pgm handles      */
  22. #define VERTICALEPSILON 450000L /* crlf when increasing v more than this   */
  23.  
  24. #define rightmargin     152    /* nr of columns allowed to the right of h=0*/
  25. #define leftmargin      -50    /* give some room for negative h-coordinate */
  26. #define LINELEN         203    /* rightmargin - leftmargin + 1 */
  27.  
  28. #define MOVE            TRUE   /* if advancing h when outputing a rule     */
  29. #define STAY            FALSE  /* if not advancing h when outputing a rule */
  30.  
  31. #define absolute        0      /* for seeking in files                     */
  32. #define relative        1
  33.  
  34. #define FORM             12    /* formfeed                                 */
  35. #define SPACE            32    /* space                                    */
  36. #define DEL             127    /* delete                                   */
  37.  
  38. #define LASTCHAR        127    /* max dvi character, above are commands    */
  39.  
  40. #define IMIN(a, b)      (a<b ? a : b)
  41. #define IMAX(a, b)      (a>b ? a : b)
  42.  
  43. #define get1()          num(1)
  44. #define get2()          num(2)
  45. #define get3()          num(3)
  46. #define get4()          num(4)
  47. #define sget1()         snum(1)
  48. #define sget2()         snum(2)
  49. #define sget3()         snum(3)
  50. #define sget4()         snum(4)
  51.  
  52. char *dvistuff = "@(#) dvistuff.c  4.1 27/03/90 M.J.E. Mol (c) 1989, 1990";
  53.  
  54. /*---------------------------------------------------------------------------*/
  55.  
  56. typedef struct {
  57.     long hh;
  58.     long vv;
  59.     long ww;
  60.     long xx;
  61.     long yy;
  62.     long zz;
  63. } stackitem;
  64.  
  65. typedef struct lineptr {        /* the lines of text to be output to outfile */
  66.     long            vv;                 /* vertical position of the line     */
  67.     int             charactercount;     /* pos of last char on line          */
  68.     struct lineptr *prev;               /* preceding line                    */
  69.     struct lineptr *next;               /* succeeding line                   */
  70.     char            text[LINELEN+1];    /* leftmargin...rightmargin          */
  71. } linetype;
  72.  
  73. typedef struct _font {
  74.     long    num;
  75.     struct _font * next;
  76.     char  * name;
  77. } font;
  78.  
  79.  
  80. /*---------------------------------------------------------------------------*/
  81.  
  82. bool        pageswitchon;       /* true if user-set pages to print           */
  83. bool        sequenceon;         /* false if pagesw-nrs refers to TeX-nrs     */
  84. bool        scascii;            /* if true make Scand. nat. chars right      */
  85. bool        noffd;              /* if true output ^L instead of formfeed     */
  86.  
  87. int         opcode;             /* dvi-opcodes                               */
  88.  
  89. long        h, v;               /* coordinates, horizontal and vertical      */
  90. long        w, x, y, z;         /* horizontal and vertical amounts           */
  91.  
  92. long        pagecounter;        /* sequence page number counter              */
  93. long        backpointer;        /* pointer for offset to previous page       */
  94. long        pagenr;             /* TeX page number                           */
  95. int         stackmax;           /* stacksize required                        */
  96.  
  97. long        maxpagewidth;       /* width of widest page in file              */
  98. long        charwidth;          /* aprox width of character                  */
  99.  
  100. linetype *  currentline;        /* pointer to current line on current page   */
  101. linetype *  firstline;          /* pointer to first line on current page     */
  102. linetype *  lastline;           /* pointer to last line on current page      */
  103. int         firstcolumn;        /* 1st column with something to print        */
  104.  
  105. stackitem * stack;              /* stack for dvi-pushes                      */
  106. int         sptr;               /* stack pointer                             */
  107.  
  108. font * fonts = NULL;            /* List of fontnames defined                 */
  109. int  symbolfont = FALSE;        /* true if font is a symbol font             */
  110.  
  111. /*---------------------------------------------------------------------------*/
  112.  
  113. #if defined(MSDOS)
  114. void            postamble       (void);
  115. void            preamble        (void);
  116. void            walkpages       (void);
  117. void            initpage        (void);
  118. void            dopage          (void);
  119. void            skippage        (void);
  120. void            printpage       (void);
  121. bool            inlist          (long);
  122. void            rule            (bool, long, long);
  123. void            ruleaux         (long, long, char);
  124. long            horizontalmove  (long);
  125. int             skipnops        (void);
  126. linetype    *   getline         (void);
  127. linetype    *   findline        (void);
  128. unsigned long   num             (int);
  129. long            snum            (int);
  130. void            dochar          (char);
  131. void            symchar         (char);
  132. void            normchar        (char);
  133. void            outchar         (char);
  134. void            putcharacter    (long);
  135. void            setchar         (long);
  136. void            fontdef         (int);
  137. void            setfont         (long);
  138. #else
  139. void            postamble       ();
  140. void            preamble        ();
  141. void            walkpages       ();
  142. void            initpage        ();
  143. void            dopage          ();
  144. void            skippage        ();
  145. void            printpage       ();
  146. bool            inlist          ();
  147. void            rule            ();
  148. void            ruleaux         ();
  149. long            horizontalmove  ();
  150. int             skipnops        ();
  151. linetype    *   getline         ();
  152. linetype    *   findline        ();
  153. unsigned long   num             ();
  154. long            snum            ();
  155. void            dochar          ();
  156. void            symchar         ();
  157. void            normchar        ();
  158. void            outchar         ();
  159. void            putcharacter    ();
  160. void            setchar         ();
  161. void            fontdef         ();
  162. void            setfont         ();
  163. #if defined(VMS)
  164. long        vmsseek        ();
  165. long        vms_ftell    ();
  166. long        vms_ungetc    ();
  167. #endif
  168. #endif
  169.  
  170.  
  171. /*---------------------------------------------------------------------------*/
  172. /*---------------------------------------------------------------------------*/
  173.  
  174. /*
  175.  * The main function for processing the dvi file.
  176.  * Here we assume there are to file pointers: DVIfile and output.
  177.  * Also we have a list of pages pointed to by 'currentpage',
  178.  * which is only used (in 'inlist()') when a page list is given.
  179.  */
  180.  
  181. void dvimain()
  182. {
  183.  
  184.     postamble();                            /* seek and process the postamble */
  185.     /* note that walkpages *must* immediately follow preamble */
  186.     preamble();                             /* process preamble               */
  187.     walkpages();                            /* time to do the actual work!    */
  188.  
  189. } /* dvimain */
  190.  
  191. /*---------------------------------------------------------------------------*/
  192.  
  193. void postamble()            /* find and process postamble, use random access */
  194. {
  195.     register long size;
  196.     register int  count;
  197.     struct stat st;
  198.  
  199.     fstat (fileno(DVIfile), &st);
  200.     size = (long) st.st_size;                   /* get size of file          */
  201.     count = -1;
  202.     do {              /* back file up past signature bytes (223), to id-byte */
  203.         if (size == 0)
  204.             errorexit(nopst);
  205.         size--;
  206.         mseek(DVIfile, size, absolute);
  207.         opcode = (int) get1();
  208.         count++;
  209.     } while (opcode == TRAILER);
  210.     if (count < 4) {                            /* must have 4 trailer bytes */
  211.          foo = count;
  212.          errorexit(fwsgn);
  213.     }
  214.     if (opcode != VERSIONID)
  215.         errorexit(badid);
  216.     mseek(DVIfile, size-4, absolute);       /* back up to back-pointer       */
  217.     mseek(DVIfile, sget4(), absolute);      /* and to start of postamble   */
  218.     if (get1() != POST)
  219.         errorexit(nopst);
  220.     mseek(DVIfile, 20L, relative); /* lastpageoffset, numerator, denominator */
  221.                                    /* magnification, maxpageheight           */
  222.     maxpagewidth = sget4();
  223.     charwidth = maxpagewidth / (ttywidth + espace); 
  224.     stackmax = (int) get2();
  225.     if ((stack = (stackitem *) malloc(stackmax * sizeof(stackitem))) == NULL)
  226.        errorexit(stkrq);
  227.  
  228.     /* get2() -- totalpages */
  229.     /* fontdefs  do fontdefs in flight ... */
  230.  
  231. } /* postamble */
  232.  
  233. /*---------------------------------------------------------------------------*/
  234.  
  235. void preamble()                 /* process preamble, use random access       */
  236. {
  237.  
  238.     mseek(DVIfile, 0L, absolute);       /* read the dvifile from the start   */
  239.     if ((opcode = skipnops()) != PRE)
  240.         errorexit(nopre);
  241.     opcode = (int) get1();        /* check id in preamble, ignore rest of it */
  242.     if (opcode != VERSIONID)
  243.         errorexit(badid);
  244.     mseek(DVIfile, 12L, relative);  /* numerator, denominator, magnification */
  245.     mseek(DVIfile, get1(), relative);         /* skip job identification     */
  246.  
  247. } /* preamble */
  248.  
  249. /*----------------------------------------------------------------------------*/
  250.  
  251. void walkpages()                  /* process the pages in the DVI-file */
  252. {
  253.     register bool wantpage;
  254.  
  255.     pagecounter = 0L;
  256.     while ((opcode = skipnops()) != POST) {
  257.         if (opcode != BOP)              /* should be at start of page now    */
  258.             errorexit(nobop);
  259.         else {
  260.             pagecounter++;
  261.             pagenr = sget4();           /* get TeX page number               */
  262.             mseek(DVIfile, 36L, relative); /* skip page header */
  263.             backpointer = sget4();      /* get previous page offset          */
  264.             if (pageswitchon)
  265.                 if (sequenceon)
  266.                     wantpage = inlist(pagecounter);
  267.                 else
  268.                     wantpage = inlist(pagenr);
  269.             else
  270.                 wantpage = TRUE;
  271.  
  272.             if (wantpage) {
  273.                 initpage();
  274.                 dopage();
  275.                 printpage();
  276.             }
  277.             else {
  278.                 skippage();
  279.             }
  280.         }
  281.     }
  282.  
  283. } /* walkpages */
  284.  
  285. /*---------------------------------------------------------------------------*/
  286.  
  287. void initpage()
  288. {
  289.  
  290.     h = 0L;  v = 0L;                        /* initialize coordinates   */
  291.     x = 0L;  w = 0L;  y = 0L;  z = 0L;      /* initialize amounts       */
  292.     sptr = 0;                               /* initialize stack         */
  293.     currentline = getline();                /* initialize list of lines */
  294.     currentline->vv = 0L;
  295.     firstline   = currentline;
  296.     lastline    = currentline;
  297.     firstcolumn = rightmargin;
  298.     if (pageswitchon) {
  299.         if ((sequenceon && (pagecounter != firstpage->pag)) ||
  300.             (!sequenceon && (pagenr != firstpage->pag)))
  301.             if (noffd)
  302.                 fprintf(output, "^L\n");
  303.             else
  304.                 putc(FORM, output);
  305.     }
  306.     else
  307.         if (backpointer != -1)              /* not FORM at first page   */
  308.             if (noffd)
  309.                 fprintf(output, "^L\n");
  310.             else
  311.                 putc(FORM, output);
  312.  
  313. } /* initpage */
  314.  
  315. /*----------------------------------------------------------------------------*/
  316.  
  317. void dopage()
  318. {
  319.  
  320.     while ((opcode = (int) get1()) != EOP) {    /* process page until eop */
  321.         if (opcode <= LASTCHAR)
  322.             dochar((char) opcode);
  323.         else if ((opcode >= FONT_00) && (opcode <= FONT_63)) 
  324.             setfont(opcode - FONT_00);
  325.         else if (opcode > POST_POST)
  326.             errorexit(illop);
  327.         else
  328.             switch (opcode) {
  329.                 case SET1     : setchar(get1()); break;
  330.                 case SET2     : setchar(get2()); break;
  331.                 case SET3     : setchar(get3()); break;
  332.                 case SET4     : setchar(get4()); break;
  333.                 case SET_RULE : { long height = sget4();
  334.                                   rule(MOVE, sget4(), height); break;
  335.                                 }
  336.                 case PUT1     : putcharacter(get1()); break;
  337.                 case PUT2     : putcharacter(get2()); break;
  338.                 case PUT3     : putcharacter(get3()); break;
  339.                 case PUT4     : putcharacter(get4()); break;
  340.                 case PUT_RULE : { long height = sget4();
  341.                                   rule(STAY, sget4(), height); break;
  342.                                 }
  343.                 case NOP      : break;  /* no-op */
  344.                 case BOP      : errorexit(bdbop); break;
  345. /*              case EOP      : break;  strange place to have EOP */
  346.                 case PUSH     : if (sptr >= stackmax)            /* push */
  347.                                      errorexit(stkof);
  348.                                 stack[sptr].hh = h;
  349.                                 stack[sptr].vv = v;
  350.                                 stack[sptr].ww = w;
  351.                                 stack[sptr].xx = x;
  352.                                 stack[sptr].yy = y;
  353.                                 stack[sptr].zz = z;
  354.                                 sptr++;
  355.                                 break;
  356.                 case POP      : if (sptr == 0)                   /* pop */
  357.                                     errorexit(stkuf);
  358.                                 sptr--;
  359.                                 h = stack[sptr].hh;
  360.                                 v = stack[sptr].vv;
  361.                                 w = stack[sptr].ww;
  362.                                 x = stack[sptr].xx;
  363.                                 y = stack[sptr].yy;
  364.                                 z = stack[sptr].zz;
  365.                                 break;
  366.                 case RIGHT1   : (void) horizontalmove(sget1()); break;
  367.                 case RIGHT2   : (void) horizontalmove(sget2()); break;
  368.                 case RIGHT3   : (void) horizontalmove(sget3()); break;
  369.                 case RIGHT4   : (void) horizontalmove(sget4()); break;
  370.                 case W0       : h += w; break;
  371.                 case W1       : w = horizontalmove(sget1()); break;
  372.                 case W2       : w = horizontalmove(sget2()); break;
  373.                 case W3       : w = horizontalmove(sget3()); break;
  374.                 case W4       : w = horizontalmove(sget4()); break;
  375.                 case X0       : h += x; break;
  376.                 case X1       : x = horizontalmove(sget1()); break;
  377.                 case X2       : x = horizontalmove(sget2()); break;
  378.                 case X3       : x = horizontalmove(sget3()); break;
  379.                 case X4       : x = horizontalmove(sget4()); break;
  380.                 case DOWN1    : v += sget1(); break;
  381.                 case DOWN2    : v += sget2(); break;
  382.                 case DOWN3    : v += sget3(); break;
  383.                 case DOWN4    : v += sget4(); break;
  384.                 case Y0       : v += y; break;
  385.                 case Y1       : y = sget1(); v += y; break;
  386.                 case Y2       : y = sget2(); v += y; break;
  387.                 case Y3       : y = sget3(); v += y; break;
  388.                 case Y4       : y = sget4(); v += y; break;
  389.                 case Z0       : v += z; break;
  390.                 case Z1       : z = sget1(); v += z; break;
  391.                 case Z2       : z = sget2(); v += z; break;
  392.                 case Z3       : z = sget3(); v += z; break;
  393.                 case Z4       : z = sget4(); v += z; break;
  394.                 case FNT1     :
  395.                 case FNT2     :
  396.                 case FNT3     :
  397.                 case FNT4     : setfont(num(opcode - FNT1 + 1));
  398.                                 break;
  399.                 case XXX1     : mseek(DVIfile, get1(), relative); break;
  400.                 case XXX2     : mseek(DVIfile, get2(), relative); break;
  401.                 case XXX3     : mseek(DVIfile, get3(), relative); break;
  402.                 case XXX4     : mseek(DVIfile, get4(), relative); break;
  403.                 case FNT_DEF1 :
  404.                 case FNT_DEF2 :
  405.                 case FNT_DEF3 :
  406.                 case FNT_DEF4 : fontdef(opcode - FNT_DEF1 + 1);
  407.                                 break;
  408.                 case PRE      : errorexit(bdpre); break;
  409.                 case POST     : errorexit(bdpst); break;
  410.                 case POST_POST: errorexit(bdpp); break;
  411.             }
  412.     }
  413.  
  414. } /* dopage */
  415.  
  416. /*----------------------------------------------------------------------------*/
  417.  
  418. void skippage()                /* skip past one page */
  419. {
  420.     register int opcode;
  421.  
  422.     while ((opcode = (int) get1()) != EOP) {
  423.         if (opcode > POST_POST)
  424.             errorexit(illop);
  425.         else
  426.             switch (opcode) {
  427.                 case SET1     :
  428.                 case PUT1     :
  429.                 case RIGHT1   :
  430.                 case W1       :
  431.                 case X1       :
  432.                 case DOWN1    :
  433.                 case Y1       :
  434.                 case Z1       : /* assume FNT change can also be skipped */
  435.                 case FNT1     : mseek(DVIfile, 1L, relative); break;
  436.                 case SET2     :
  437.                 case PUT2     :
  438.                 case RIGHT2   :
  439.                 case W2       :
  440.                 case X2       :
  441.                 case DOWN2    :
  442.                 case Y2       :
  443.                 case Z2       :
  444.                 case FNT2     : mseek(DVIfile, 2L, relative); break;
  445.                 case SET3     :
  446.                 case PUT3     :
  447.                 case RIGHT3   :
  448.                 case W3       :
  449.                 case X3       :
  450.                 case DOWN3    :
  451.                 case Y3       :
  452.                 case Z3       :
  453.                 case FNT3     : mseek(DVIfile, 3L, relative); break;
  454.                 case SET4     :
  455.                 case PUT4     :
  456.                 case RIGHT4   :
  457.                 case W4       :
  458.                 case X4       :
  459.                 case DOWN4    :
  460.                 case Y4       :
  461.                 case Z4       :
  462.                 case FNT4     : mseek(DVIfile, 4L, relative); break;
  463.                 case SET_RULE :
  464.                 case PUT_RULE : mseek(DVIfile, 8L, relative); break;
  465.                 case BOP      : errorexit(bdbop); break;
  466.                 case XXX1     : mseek(DVIfile, get1(), relative); break;
  467.                 case XXX2     : mseek(DVIfile, get2(), relative); break;
  468.                 case XXX3     : mseek(DVIfile, get3(), relative); break;
  469.                 case XXX4     : mseek(DVIfile, get4(), relative); break;
  470.                 case FNT_DEF1 :
  471.                 case FNT_DEF2 :
  472.                 case FNT_DEF3 :
  473.                 case FNT_DEF4 : fontdef(opcode - FNT_DEF1 + 1); break;
  474.                 case PRE      : errorexit(bdpre); break;
  475.                 case POST     : errorexit(bdpst); break;
  476.                 case POST_POST: errorexit(bdpp); break;
  477.         }
  478.     }
  479.  
  480. } /* skippage */
  481.  
  482. /*---------------------------------------------------------------------------*/
  483.  
  484. void printpage()       /* 'end of page', writes lines of page to output file */
  485. {
  486.     register int  i, j;
  487.     register char ch;
  488.  
  489.     if (sptr != 0)
  490.         fprintf(stderr, "dvi2tty: warning - stack not empty at eop.\n");
  491.     for (currentline = firstline; currentline != nil;
  492.           currentline = currentline->next) {
  493.         if (currentline != firstline) {
  494.             foo = ((currentline->vv - currentline->prev->vv)/VERTICALEPSILON)-1;
  495.             if (foo > 3)
  496.                 foo = 3;        /* linespacings not too large */
  497.             for (i = 1; i <= (int) foo; i++)
  498.                 putc('\n', output);
  499.         }
  500.         if (currentline->charactercount >= leftmargin) {
  501.             foo = ttywidth - 2;
  502.             for (i = firstcolumn, j = 1; i <= currentline->charactercount;
  503.                    i++, j++) {
  504.                 ch = currentline->text[i - leftmargin];
  505.                 if (ch >= SPACE)
  506.                     putc(ch, output);
  507.                 if ((j > (int) foo) && (currentline->charactercount > i+1)) {
  508.                         fprintf(output, "*\n");         /* if line to large */
  509.                         fprintf(output, " *");          /* mark output      */
  510.                         j = 2;
  511.                 }
  512.             } 
  513.         }
  514.         putc('\n', output);
  515.     } 
  516.  
  517.     currentline = firstline;
  518.     while (currentline->next != nil) {
  519.         currentline = currentline->next;
  520.         free(currentline->prev);
  521.     }
  522.     free(currentline);              /* free last line */
  523.     currentline = nil;
  524.  
  525. } /* printpage */
  526.  
  527. /*----------------------------------------------------------------------------*/
  528.  
  529. bool inlist(pagenr)                         /* ret true if in list of pages */
  530. register long pagenr;
  531. {
  532.  
  533.     while ((currentpage->pag < 0) && (currentpage->pag != pagenr) &&
  534.            !currentpage->all && (currentpage->nxt != nil))
  535.         currentpage = currentpage->nxt;
  536.     if ((currentpage->all && (pagenr < currentpage->pag)) ||
  537.          (currentpage->pag == pagenr))
  538.             return TRUE;
  539.     else if (pagenr > 0) {
  540.         while ((currentpage->pag < pagenr) && (currentpage->nxt != nil))
  541.             currentpage = currentpage->nxt;
  542.         if (currentpage->pag == pagenr)
  543.             return TRUE;
  544.     }
  545.     return FALSE;
  546.  
  547. } /* inlist */
  548.  
  549. /*----------------------------------------------------------------------------*/
  550.  
  551. void rule(moving, rulewt, ruleht)
  552. register bool moving;
  553. register long rulewt, ruleht;
  554. {   /* output a rule (vertical or horizontal), increment h if moving is true */
  555.  
  556.     register char ch;               /* character to set rule with            */
  557.     register long saveh, savev;
  558.                               /* rule   --   starts up the recursive routine */
  559.     if (!moving)
  560.         saveh = h;
  561.     if ((ruleht <= 0) || (rulewt <= 0))
  562.         h += rulewt;
  563.     else {
  564.         savev = v;
  565.         if ((ruleht / rulewt) > 0)         /* value < 1 truncates to 0 */
  566.             ch = '|';
  567.         else if (ruleht > (VERTICALEPSILON / 2))
  568.             ch = '=';
  569.         else
  570.             ch = '_';
  571.         ruleaux(rulewt, ruleht, ch);
  572.         v = savev;
  573.     }
  574.     if (!moving)
  575.         h = saveh;
  576.  
  577. } /* rule */
  578.  
  579.  
  580.  
  581. void ruleaux(rulewt, ruleht, ch)     /* recursive  that does the job */
  582. register long rulewt, ruleht;
  583. register char ch;
  584. {
  585.     register long wt, lmh, rmh;
  586.  
  587.     wt = rulewt;
  588.     lmh = h;                        /* save left margin                      */
  589.     if (h < 0) {                    /* let rules that start at negative h    */
  590.         wt -= h;                    /* start at coordinate 0, but let it     */
  591.         h = 0;                      /*   have the right length               */
  592.     }
  593.     while (wt > 0) {                /* output the part of the rule that      */
  594.         rmh = h;                    /*   goes on this line                   */
  595.         outchar(ch);
  596.         wt -= (h-rmh);              /* decrease the width left on line       */
  597.     }
  598.     ruleht -= VERTICALEPSILON;      /* decrease the height                   */
  599.     if (ruleht > VERTICALEPSILON) { /* still more vertical?                  */
  600.         rmh = h;                    /* save current h (right margin)         */
  601.         h = lmh;                    /* restore left margin                   */
  602.         v -= (VERTICALEPSILON + VERTICALEPSILON / 10);
  603.         ruleaux(rulewt, ruleht, ch);
  604.         h = rmh;                    /* restore right margin                  */
  605.     }
  606.  
  607. } /* ruleaux */
  608.  
  609. /*----------------------------------------------------------------------------*/
  610.  
  611. long horizontalmove(amount)
  612. register long amount;
  613. {
  614.  
  615. #if defined(MSDOS)
  616.     if (labs(amount) > charwidth / 4L) {
  617. #else
  618.     if (abs(amount) > charwidth / 4L) {
  619. #endif
  620.         foo = 3*charwidth / 4;
  621.         if (amount > 0)
  622.             amount = ((amount+foo) / charwidth) * charwidth;
  623.         else
  624. #if defined(VMS)
  625.             amount = (ROUND( (float) (amount-foo) / charwidth) + 1)* charwidth;
  626. #else
  627.             amount = ((amount-foo) / charwidth) * charwidth;
  628. #endif
  629.         h += amount;
  630.         return amount;
  631.     }
  632.     else
  633.         return 0;
  634.  
  635. }   /* horizontalmove */
  636.  
  637. /*----------------------------------------------------------------------------*/
  638.  
  639. int skipnops()                      /* skips by no-op commands  */
  640. {
  641.     register int opcode;
  642.  
  643.     while ((opcode = (int) num(1)) == NOP);
  644.     return opcode;
  645.  
  646. } /* skipnops */
  647.  
  648. /*----------------------------------------------------------------------------*/
  649.  
  650. linetype *getline()             /* returns an initialized line-object */
  651. {
  652.     register int  i;
  653.     register linetype *temp;
  654.  
  655.     if ((temp = (linetype *) malloc(sizeof(linetype))) == NULL) 
  656.         errorexit(lnerq);
  657.     temp->charactercount = leftmargin - 1;
  658.     temp->prev = nil;
  659.     temp->next = nil;
  660.     for (i = 0; i < LINELEN; i++)
  661.         temp->text[i] = ' ';
  662.     temp->text[i] = '\0';
  663.     return temp;
  664.  
  665. } /* getline */
  666.  
  667. /*----------------------------------------------------------------------------*/
  668.  
  669. linetype *findline()            /* find best fit line were text should go */
  670. {                               /* and generate new line if needed        */
  671.     register linetype *temp;
  672.     register long topd, botd;
  673.  
  674.     if (v <= firstline->vv) {                      /* above first line */
  675.         if (firstline->vv - v > VERTICALEPSILON) {
  676.             temp = getline();
  677.             temp->next = firstline;
  678.             firstline->prev = temp;
  679.             temp->vv = v;
  680.             firstline = temp;
  681.         }
  682.         return firstline;
  683.     }
  684.  
  685.     if (v >= lastline->vv) {                       /* below last line */
  686.         if (v - lastline->vv > VERTICALEPSILON) {
  687.             temp = getline();
  688.             temp->prev = lastline;
  689.             lastline->next = temp;
  690.             temp->vv = v;
  691.             lastline = temp;
  692.         }
  693.         return lastline;
  694.     }
  695.  
  696.     temp = lastline;                               /* in between two lines */
  697.     while ((temp->vv > v) && (temp != firstline))
  698.         temp = temp->prev;
  699.  
  700.     /* temp->vv < v < temp->next->vv --- temp is above, temp->next is below */
  701.     topd = v - temp->vv;
  702.     botd = temp->next->vv - v;
  703.     if ((topd < VERTICALEPSILON) || (botd < VERTICALEPSILON))
  704.         if (topd < botd)                           /* take best fit */
  705.             return temp;
  706.         else
  707.             return temp->next;
  708.  
  709.     /* no line fits suitable, generate a new one */
  710.     currentline = getline();
  711.     currentline->next = temp->next;
  712.     currentline->prev = temp;
  713.     temp->next->prev = currentline;
  714.     temp->next = currentline;
  715.     currentline->vv = v;
  716.     return currentline;
  717.  
  718. } /* findline */
  719.  
  720. /*----------------------------------------------------------------------------*/
  721.  
  722. unsigned long num(size)
  723. register int size;
  724. {
  725.     register int i;
  726.     register long x = 0;
  727.  
  728.     for (i = 0; i < size; i++)
  729.         x = (x << 8) + (unsigned) getc(DVIfile);
  730.     return x;
  731.  
  732. } /* num */
  733.  
  734.  
  735. long snum(size)
  736. register int size;
  737. {
  738.     register int i;
  739.     register long x = 0;
  740.  
  741.     x = getc(DVIfile);
  742.     if (x & 0x80)
  743.         x -= 0x100;
  744.     for (i = 1; i < size; i++)
  745.         x = (x << 8) + (unsigned) getc(DVIfile);
  746.     return x;
  747.  
  748. } /* snum */
  749.  
  750. /*----------------------------------------------------------------------------*/
  751.  
  752. void dochar(ch)
  753. register char ch;
  754. {
  755.  
  756.     if (symbolfont == TRUE)
  757.         symchar(ch);
  758.     else
  759.         normchar(ch);
  760.  
  761.     return;
  762.  
  763. } /* dochar */
  764.  
  765.  
  766.  
  767. void symchar(ch)                     /* output ch to appropriate line */
  768. register char ch;
  769. {
  770.  
  771.     switch (ch) {       /* can do a lot more on MSDOS machines ... */
  772.        case   0: ch = '-'; break;
  773.        case   1: ch = '.'; break;
  774.        case   2: ch = 'x'; break;
  775.        case   3: ch = '*'; break;
  776.        case  13: ch = 'O'; break;
  777.        case  14: ch = 'O'; break;
  778.        case  15: ch = 'o'; break;
  779.        case  24: ch = '~'; break;
  780.        case 102: ch = '{'; break;
  781.        case 103: ch = '}'; break;
  782.        case 104: ch = '<'; break;
  783.        case 105: ch = '>'; break;
  784.        case 106: ch = '|'; break;
  785.        case 110: ch = '\\'; break;
  786.     }
  787.     outchar(ch);
  788.  
  789.     return;
  790.  
  791. } /* symchar */
  792.  
  793.  
  794.  
  795. void normchar(ch)
  796. register char ch;
  797. {
  798.  
  799.     switch (ch) {
  800.         case 11  :  outchar('f'); ch = 'f'; break;  /* ligature        */
  801.         case 12  :  outchar('f'); ch = 'i'; break;  /* ligature        */
  802.         case 13  :  outchar('f'); ch = 'l'; break;  /* ligature        */
  803.         case 14  :  outchar('f'); outchar('f');
  804.                                   ch = 'i'; break;  /* ligature        */
  805.         case 15  :  outchar('f'); outchar('f');
  806.                                   ch = 'l'; break;  /* ligature        */
  807.         case 16  :  ch = 'i'; break;
  808.         case 17  :  ch = 'j'; break;
  809.         case 25  :  outchar('s'); ch = 's'; break;  /* German double s */
  810.         case 26  :  outchar('a'); ch = 'e'; break;  /* Dane/Norw ae    */
  811.         case 27  :  outchar('o'); ch = 'e'; break;  /* Dane/Norw oe    */
  812.         case 28  :  if (scascii)
  813.                         ch = '|';                   /* Dane/Norw /o    */
  814.                     else
  815.                         ch = 'o';
  816.                     break;
  817.         case 29  :  outchar('A'); ch = 'E'; break;  /* Dane/Norw AE    */
  818.         case 30  :  outchar('O'); ch = 'E'; break;  /* Dane/Norw OE    */
  819.         case 31  :  if (scascii)
  820.                         ch = '\\';                  /* Dane/Norw /O    */
  821.                     else
  822.                         ch = 'O';
  823.                     break;
  824.         case 92  :  ch = '"'; break;  /* \ from `` */
  825.         case 123 :  ch = '-'; break;  /* { from -- */
  826.         case 124 :  ch = '_'; break;  /* | from --- */
  827.         case 125 :  ch = '"'; break;  /* } from \H */
  828.         case 126 :  ch = '"'; break;  /* ~ from \~ */
  829.         case 127 :  ch = '"'; break;  /* DEL from \" */
  830. #if 0
  831.         case 18  :  ch = '`'; break   /* from \` */
  832.         case 19  :  ch = ''''; break  /* from \' */
  833.         case 20  :  ch = '~'; break   /* from \v */
  834.         case 21  :  ch = '~'; break   /* from \u */
  835.         case 22  :  ch = '~'; break   /* from \= */
  836.         case 24  :  ch = ','; break   /* from \c */
  837.         case 94  :  ch = '^'; break   /* ^ from \^ */
  838.         case 95  :  ch = '`'; break   /* _ from \. */
  839. #endif
  840.     }
  841.     outchar(ch); 
  842.  
  843.     return;
  844.  
  845. } /*normchar */
  846.  
  847.  
  848.  
  849. void outchar(ch)                     /* output ch to appropriate line */
  850. register char ch;
  851. {
  852.     register int i, j;
  853.  
  854. /*     fprintf(stderr, "hor: %ld, ver: %ld\n", h, v); */
  855. #if defined(MSDOS)
  856.     if (labs(v - currentline->vv) > VERTICALEPSILON / 2L)
  857. #else
  858.     if (abs(v - currentline->vv) > VERTICALEPSILON / 2L)
  859. #endif
  860.         currentline = findline();
  861.  
  862. #if 0
  863.     j = (int) (((double) h / (double) maxpagewidth) * (ttywidth-1)) + 1;
  864. #else
  865.     j = (int) (h / charwidth);
  866. #endif
  867.     if (j > rightmargin)     /* leftmargin <= j <= rightmargin */
  868.         j = rightmargin;
  869.     else if (j < leftmargin)
  870.         j = leftmargin;
  871.     foo = leftmargin - 1;
  872.     /*
  873.     /* This code does not really belong here ...
  874.     /*
  875.     /*-------------------------------------------------------------*/
  876.     /* The following is very specialized code, it handles national */
  877.     /* Swe/Fin characters. They are respectively: a and o with two */
  878.     /* dots ("a & "o) and a with a circle (Oa). In Swe/Fin "ASCII" */
  879.     /* these characters replace }{|][ and \.  TeX outputs these by */
  880.     /* first issuing the dots or circle and then backspace and set */
  881.     /* the a or o.  When dvitty finds an a or o it searches in the */
  882.     /* near vicinity for the character codes that represent circle */
  883.     /* or dots and if one is found the corresponding national char */
  884.     /* replaces the special character codes.                       */
  885.     /*-------------------------------------------------------------*/
  886.     if (scascii) {
  887.         if ((ch == 'a') || (ch == 'A') || (ch == 'o') || (ch == 'O')) {
  888.             for (i = IMAX(leftmargin, j-2);
  889.                  i <= IMIN(rightmargin, j+2);
  890.                  i++)
  891.                 if ((currentline->text[i - leftmargin] == 127) ||
  892.                     (currentline->text[i - leftmargin] == 34) ||
  893.                     (currentline->text[i - leftmargin] == 23))
  894.                     foo = i;
  895.             if (foo >= leftmargin) {
  896.                 j = (int) foo;
  897.                 switch (currentline->text[j - leftmargin]) {
  898.                     case 127 : case 34:
  899.                                if (ch == 'a')
  900.                                    ch = '{';
  901.                                else if (ch == 'A')      /* dots ... */
  902.                                    ch = '[';
  903.                                else if (ch == 'o')
  904.                                    ch = '|';
  905.                                else if (ch == 'O')
  906.                                    ch = '\\';
  907.                                break;
  908.                     case 23  : if (ch == 'a')
  909.                                    ch = '}';
  910.                                else if (ch == 'A')      /* circle */
  911.                                    ch = ']';
  912.                                break;
  913.                 }
  914.             }
  915.         }
  916.     }
  917.     /*----------------- end of 'Scandinavian code' ----------------*/
  918.     if (foo == leftmargin-1)
  919.         while ((currentline->text[j - leftmargin] != SPACE)
  920.                && (j < rightmargin)) {
  921.             j++;
  922.             h += charwidth;
  923.         }
  924.     if ( ((ch >= SPACE) && (ch != DEL)) ||
  925.          (scascii && (ch == 23)) ) {
  926.           /*  (scascii && (ch == DEL)) ) {    if VMS ??? */
  927.         if (j < rightmargin)
  928.             currentline->text[j - leftmargin] = ch;
  929.         else
  930.             currentline->text[rightmargin - leftmargin] = '@';
  931.         if (j > currentline->charactercount)
  932.             currentline->charactercount = j;
  933.         if (j < firstcolumn)
  934.             firstcolumn = j;
  935.         h += charwidth;
  936.     }
  937.  
  938. } /* outchar */
  939.  
  940. /*----------------------------------------------------------------------------*/
  941.  
  942. void putcharacter(charnr)            /* output character, don't change h */
  943. register long charnr;
  944. {
  945.     register long saveh;
  946.  
  947.     saveh = h;
  948.     if ((charnr >= 0) && (charnr <= LASTCHAR))
  949.         outchar((char) charnr);
  950.     else
  951.         setchar(charnr);
  952.     h = saveh;
  953.  
  954. } /* putcharacter */
  955.  
  956. /*----------------------------------------------------------------------------*/
  957.  
  958. void setchar(charnr)
  959. long charnr;
  960. {    /* should print characters with character code>127 from current font */
  961.      /* note that the parameter is a dummy, since ascii-chars are<=127    */
  962.  
  963.     outchar('#');
  964.  
  965. } /* setchar */
  966.  
  967.  
  968. /*----------------------------------------------------------------------------*/
  969.  
  970.  
  971. void fontdef(x)
  972. register int x;
  973. {
  974.     register int i;
  975.     char * name;
  976.     font * fnt;
  977.     int namelen;
  978.     long fntnum;
  979.     int new = 0;
  980.  
  981.     fntnum = num(x);
  982.     (void) get4();                      /* checksum */
  983.     (void) get4();                      /* scale */
  984.     (void) get4();                      /* design */
  985.     namelen = (int) get1() + (int) get1();
  986.     fnt = fonts;
  987.     while (fnt != NULL && fnt->num != fntnum)       /* does fontnum exist */
  988.         fnt = fnt->next;
  989.     if (fnt == NULL) {
  990.         if ((fnt = (font *) malloc(sizeof(font))) == NULL) {
  991.             perror("fontdef");
  992.             exit(1);
  993.         }
  994.         fnt->num = fntnum;
  995.         new = 1;
  996.     }
  997.     else
  998.         free(fnt->name);    /* free old name */
  999.     if ((name = (char *) malloc(namelen * sizeof(char))) == NULL) {
  1000.         perror("fontdef");
  1001.         exit(1);
  1002.     }
  1003.     
  1004.     for (i = 0; i < namelen; i++)
  1005.         name[i] = get1();
  1006.     fnt->name = name;
  1007.     if (new) {
  1008.         fnt->next = fonts;
  1009.         fonts = fnt;
  1010.     }
  1011.  
  1012.     return;
  1013.  
  1014. } /* fontdef */
  1015.  
  1016.  
  1017.  
  1018. void setfont(fntnum)
  1019. long fntnum;
  1020. {
  1021.     font * fnt;
  1022.     char * s;
  1023.  
  1024.     fnt = fonts;
  1025.     while (fnt != NULL && fnt->num != fntnum)
  1026.         fnt = fnt->next;
  1027.     if (fnt == NULL) {
  1028.         /* error : font not found */
  1029.         symbolfont = FALSE;
  1030.         return;
  1031.     }
  1032.  
  1033.     s = fnt->name;
  1034.     while ((s = strchr(s, 's')) != NULL) {
  1035.         if (strncmp("sy", s, 2) == 0) {
  1036.             symbolfont = TRUE;
  1037.             return;
  1038.         }
  1039.     s++;    /* New line to fix bug; font names with 's' would hang */
  1040.     }
  1041.    
  1042.     symbolfont = FALSE;
  1043.     return;
  1044.  
  1045. } /* setfont */
  1046.    
  1047.  
  1048.  
  1049. /*----------------------------------------------------------------------------*/
  1050.  
  1051.  
  1052. #if defined(VMS)
  1053. long vmsseek(fp,n,dir)
  1054. FILE *fp;
  1055. long n;
  1056. long dir;
  1057. {
  1058.     long k,m,pos,val,oldpos;
  1059.     struct stat buffer;
  1060.  
  1061.     for (;;) {                     /*loops only once or twice*/
  1062.         switch (dir) {
  1063.             case 0:            /*from BOF*/
  1064.                     oldpos = vms_ftell(fp);
  1065.                     k = n & 511;
  1066.                     m = n >> 9;
  1067.                     if (((*fp)->_cnt) && ((oldpos >> 9) == m)) {
  1068.                         val = 0; /* still in */
  1069.                         (*fp)->_ptr = ((*fp)->_base) + k;
  1070.                         (*fp)->_cnt = 512 - k;
  1071.                     }
  1072.                     else {
  1073.                         val = fseek(fp, m << 9, 0);
  1074.                         if (val == 0) {
  1075.                             (*fp)->_cnt = 0;
  1076.                             (void) fgetc(fp);
  1077.                             (*fp)->_ptr = ((*fp)->_base) + k;
  1078.                             (*fp)->_cnt = 512 - k;
  1079.                         }
  1080.                     }
  1081.                     return(val);
  1082.  
  1083.             case 1: pos = vms_ftell(fp);
  1084.                     if (pos == EOF)
  1085.                         return (EOF);
  1086.                     n += pos;
  1087.                     dir = 0;
  1088.                     break;
  1089.  
  1090.             case 2: val = fstat(fileno(fp), &buffer);
  1091.                     if (val == EOF)
  1092.                         return (EOF);
  1093.                     n += buffer.st_size - 1;
  1094.  
  1095.                     dir = 0;
  1096.                     break;
  1097.  
  1098.             default : return (EOF);
  1099.         }
  1100.     }
  1101.  
  1102. } /* vmsseek */
  1103.         
  1104.  
  1105.  
  1106. long vms_ftell(fp)
  1107. FILE *fp;
  1108. {
  1109.     char c;
  1110.     long pos;
  1111.     long val;
  1112.     if ((*fp)->_cnt == 0) {
  1113.         c = fgetc(fp);
  1114.         val = vms_ungetc(c, fp);
  1115.         if (val != c)
  1116.             return (EOF);
  1117.     }
  1118.     pos = ftell(fp);
  1119.     if (pos >= 0)
  1120.         pos += ((*fp)->_ptr) - ((*fp)->_base);
  1121.     return (pos);
  1122.  
  1123. } /* vms_ftell */
  1124.  
  1125.  
  1126.  
  1127. long vms_ungetc(c,fp)
  1128. char c;
  1129. FILE *fp;
  1130. {
  1131.     if ((c == EOF) && feof(fp))
  1132.         return (EOF);
  1133.     else if ((*fp)->_cnt >= 512)
  1134.         return (EOF);
  1135.     else {
  1136.         (*fp)->_cnt++;
  1137.         (*fp)->_ptr--;
  1138.         *((*fp)->_ptr) = c;
  1139.         return (c);
  1140.     }
  1141.  
  1142. } /*vms_ungetc */
  1143. #endif
  1144.